
#include "CBrokerKeyList.h"

#include <core/container/LinkList.h>
#include <core/container/OrderedLevelList.h>
#include <core/strings/BaseString.h>
#include <core/sync/lock.h>
#include <core/system/system_util.h>
#include <time.h>

#include "CBondComparator.h"
#include "CBondFilter.h"
#include "CBondSorter.h"
#include "CSharedResource.h"
#include "core/time/time.h"
#include "uam/UserAccountManager.h"

using qb::base::BaseString;
using qb::base::CSLock;
using qb::base::os::fmtstr;

#define STACK_METRICS  //

typedef qb::base::OrderedLevelList<BrokerKeyInfo, CBondComparatorIndirect>
    LevelListBase;
class BrokerKeyLevelList {
  LevelListBase m_keys;

 public:
  BrokerKeyLevelList() {
    m_keys.set_option("hash_length", "3000");
    m_keys.set_option("root_expect", "40");
    m_keys.set_option("node_max", "50");
  }
  ~BrokerKeyLevelList() {}
  void SetComparator(CBondComparatorIndirect* comparator) {
    m_keys.set_comparator(comparator);
  }
  void UpdateBatch(const std::vector<BrokerKeyInfo>& keys,
                   const std::vector<bool>& addOrErase) {
    m_keys.update(keys, addOrErase);
  }
  void Insert(const BrokerKeyInfo& bki, int wh) {
    vector<BrokerKeyInfo> keys;
    keys.push_back(bki);
    vector<bool> addOrErase;
    addOrErase.push_back(true);
    m_keys.update(keys, addOrErase);
  }
  void Erase(const BrokerKeyInfo& bki) {
    vector<BrokerKeyInfo> keys;
    keys.push_back(bki);
    vector<bool> addOrErase;
    addOrErase.push_back(false);
    m_keys.update(keys, addOrErase);
  }
  bool IsExist(const BrokerKeyInfo& bki) { return m_keys.exist(bki); }

  void BeginPush(int capcity) { m_keys.begin_push(capcity); }
  void Push(const BrokerKeyInfo& bki) { m_keys.push(bki); }
  void EndPush(bool) { m_keys.end_push(); }

  int GetCount() const { return m_keys.size(); }
  int GetKeys(int row, int count, BrokerKeyInfo* keys) {
    int pos = -1;
    return m_keys.get(row, count, keys, &pos);
  }
  int GetAllKeys(vector<BrokerKeyInfo>& allkeys) {
    allkeys.reserve(m_keys.size());
    LevelListBase::iterator it = m_keys.begin();
    for (; it != m_keys.end(); ++it) {
      allkeys.push_back(*it);
    }
    return allkeys.size();
  }

 public:
  void SetCheckFlag(bool check) {}
  void SetBrokerId(int brokerId) {}
  int GetVersion(const BrokerKeyInfo& k) { return 0; }
  // bool CheckUnique(){ return true; }
  // bool CheckState(){ return true; }
  // bool CheckSort(){ return true; }
  // bool CheckLink(){ return true; }
  // bool CheckLength(){ return true; }
};

typedef std::vector<BrokerKeyInfo> CBrokerKeyCache;
class BrokerKeyListImpl {
  enum kAction {
    kActionInsert,
    kActionCompare,
    kActionErase,
    kActionExist,
    kActionBeginPush,
    kActionPush,
    kActionEndPush,
    kActionGetKeys,
    kActionGetAllKeys,
    kActionCount
  };
  class SpeedGenerator {
    struct Impulse {
      Impulse* next;
      Impulse* prev;
      double time;
      double last;

     public:
      Impulse* GetNext() const { return next; }
      Impulse* GetPrev() const { return prev; }
      void SetNext(Impulse* n) { next = n; }
      void SetPrev(Impulse* p) { prev = p; }
    };
    typedef qb::base::DoubleLinkList<Impulse> ImpulseQueue;
    ImpulseQueue m_queue;
    ImpulseQueue m_cache;
    vector<double> m_gaps;
    double m_max_gap;

   public:
    SpeedGenerator() {}
    ~SpeedGenerator() {
      ClearQueue(m_queue);
      ClearQueue(m_cache);
    }
    void AddGaps(const std::vector<int>& seconds) {
      for (auto it = seconds.begin(); it != seconds.end(); ++it) {
        m_gaps.push_back(*it * 1000000);
      }
      std::sort(m_gaps.begin(), m_gaps.end());
      std::unique(m_gaps.begin(), m_gaps.end());
      if (!m_gaps.empty()) m_max_gap = m_gaps.at(m_gaps.size() - 1);
    }
    void ClearGaps() {
      m_gaps.clear();
      m_max_gap = 0.0;
    }

    void AddTime(double last) {
      Impulse* pulse = NewImpulse(last);
      m_queue.Append(pulse);
      RemoveBefore(pulse->time - m_max_gap);
    }
    void GetGaps(vector<int>& gaps) {
      gaps.clear();
      for (auto it = m_gaps.begin(); it != m_gaps.end(); ++it)
        gaps.push_back(*it / 1000000);
    }
    bool GetSpeeds(vector<double>& speeds) {
      double cur = HighResTime();
      speeds.clear();
      for (auto it = m_gaps.begin(); it != m_gaps.end(); ++it) {
        int ncount =
            (*it == m_max_gap) ? m_queue.GetCount() : CountAfter(cur - *it);
        double speed = ncount;
        speeds.push_back(speed);
      }
      return true;
    }

   protected:
    void ClearQueue(ImpulseQueue& queue) {
      while (queue.GetHead()) {
        Impulse* head = queue.PickHead();
        if (head) delete head;
      }
    }
    int CountAfter(double time) const {
      int ncount = 0;
      Impulse* pulse = m_queue.GetTail();
      while (pulse && pulse->time > time) {
        ncount++;
        pulse = pulse->GetPrev();
      }
      return ncount;
    }
    void RemoveBefore(double time) {
      while (m_queue.GetHead() && m_queue.GetHead()->time < time) {
        m_cache.Append(m_queue.PickHead());
      }
    }
    Impulse* NewImpulse(double last) {
      Impulse* pulse = m_cache.PickHead();
      if (pulse == nullptr) pulse = new Impulse();
      pulse->time = HighResTime();
      pulse->last = last;
      pulse->time -= last;
      pulse->next = nullptr;
      pulse->prev = nullptr;
      return pulse;
    }
  };

#define ACTION_TIME(ACT)  // ScopedActionTimer _scoped_act(ACT,&m_stat)
  typedef qb::base::HighResTime HighResTime;
  BrokerKeyLevelList* m_level;
  HighResTime m_timer;

 public:
  BrokerKeyListImpl() : m_level(nullptr) { m_level = new BrokerKeyLevelList(); }
  ~BrokerKeyListImpl() {
    if (m_level) delete m_level;
    m_level = nullptr;
  }
  void SetComparator(CBondComparatorIndirect* comparator) {
    m_level->SetComparator(comparator);
  }
  void UpdateBatch(const std::vector<BrokerKeyInfo>& keys,
                   const std::vector<bool>& addOrErase) {
    {
      HighResTime timer;
      ACTION_TIME(kActionInsert);
      if (m_level) m_level->UpdateBatch(keys, addOrErase);
    }
  }
  void Insert(const BrokerKeyInfo& bki, int wh) {
    {
      HighResTime timer;
      ACTION_TIME(kActionInsert);
      if (m_level) m_level->Insert(bki, wh);
    }
  }
  int CompareBond(CBondSorter* sorter, const BrokerKeyInfo& b1,
                  const BrokerKeyInfo& b2) {
    return sorter->CompareRecordDirectly(b1, b2);
  }
  void Erase(const BrokerKeyInfo& bki) {
    ACTION_TIME(kActionErase);
    if (m_level) m_level->Erase(bki);
  }
  bool IsExist(const BrokerKeyInfo& bki) {
    ACTION_TIME(kActionExist);
    return m_level->IsExist(bki);
  }

  void BeginPush(int capcity) {
    m_timer = HighResTime();
    ACTION_TIME(kActionBeginPush);
    if (m_level) m_level->BeginPush(capcity);
  }
  void Push(const BrokerKeyInfo& bki) {
    // ACTION_TIME(kActionPush);
    if (m_level) m_level->Push(bki);
  }
  void EndPush(bool b) {
    ACTION_TIME(kActionEndPush);
    if (m_level) m_level->EndPush(b);
    // BLOGINFO("[JUMPLIST]Push last %8d us", m_timer.elapsed().microsec());
  }

  int GetCount() const { return m_level->GetCount(); }
  int GetKeys(int row, int count, BrokerKeyInfo* keys) {
    ACTION_TIME(kActionGetKeys);
    return m_level->GetKeys(row, count, keys);
  }
  int GetAllKeys(vector<BrokerKeyInfo>& allkeys) {
    m_timer = HighResTime();
    ACTION_TIME(kActionGetAllKeys);
    m_level->GetAllKeys(allkeys);
    // BLOGINFO("[JUMPLIST]GetAllKeys last %8d us",
    // m_timer.elapsed().microsec());
    return allkeys.size();
  }

 public:
  void SetCheckFlag(bool check) {}
  void SetBrokerId(int brokerId) {}
  int GetVersion(const BrokerKeyInfo& k) { return 0; }
};
////////////////////////////////////////////////////////////////////////////////
void GetColumnOrders(const CSortInfoManager& sortinfo,
                     vector<ColumnOrder>& orders) {
  orders.clear();
  bool code_found = true;
  for (int i = 0; i < (int)sortinfo.m_vecSortInfo.size(); i++) {
    ColumnOrder co;
    co.comlumn = sortinfo.m_vecSortInfo.at(i).m_nSortKey;
    co.ascend = !sortinfo.m_vecSortInfo.at(i).m_bDesc;
    code_found = code_found ? true : (co.comlumn == VBOND_CODE);
    orders.push_back(co);
  }

  // 当VBOND_CODE不存在的时候,自动按照VBOND_CODE排序
  if (1 && !code_found) {
    // VBOND_CODE
    ColumnOrder co;
    co.comlumn = VBOND_CODE;
    co.ascend = true;
    orders.push_back(co);
  }
}

////////////////////////////////////////////////////////////////////////////////

CBrokerKeyList::CBrokerKeyList(const CSortInfoManager& sortInfo, int brokerid)
    : m_sort_info(sortInfo) {
  // m_keys = new BrokerKeyJumpList(0,40,40000);
  m_keys = new BrokerKeyListImpl();
  m_keys->SetCheckFlag(false);
  m_keys->SetComparator(new CBondComparatorIndirect(this));
  m_keys->SetBrokerId(brokerid);
  m_bond_sorter = new CBondSorter();
  m_searchType = CBondContainer::typeNone;
}

CBrokerKeyList::~CBrokerKeyList() {
  if (m_keys) {
    delete m_keys;
    m_keys = 0;
  }
  if (m_bond_sorter) {
    delete m_bond_sorter;
    m_bond_sorter = 0;
  }
}

void CBrokerKeyList::SetSearchString(int nType, const char* sSearch) {
  m_searchType = nType;
  m_searchString = sSearch;
}

int CBrokerKeyList::CompareBond(const BrokerKeyInfo& b1,
                                const BrokerKeyInfo& b2) {
  return m_keys->CompareBond(m_bond_sorter, b1, b2);
  // return m_bond_sorter->CompareRecordDirectly(b1,b2);
}

void CBrokerKeyList::OnBrokerKeyFound(BondID bid, const char* brokerid,
                                      void* context) {
  ((CBrokerKeyCache*)context)->push_back(BrokerKeyInfo(brokerid, bid));
}

void CBrokerKeyList::Reloads(CBondSource* source, CBondFilter* filter) {
  STACK_METRICS("Reloads");
  // CSharedResourcePtr<CBrokerKeyCache> cache_ptr;
  CBrokerKeyCache cache;
  CBrokerKeyCache* cache_ptr = &cache;
  bool special_key = false;

  // if (dynamic_cast<CBondSourceStatic*>(source))
  //{
  //	CBondSourceStatic* src = dynamic_cast<CBondSourceStatic*>(source);
  //	const std::string& key = src->GetSearchKey();
  //	if (strstr(key.c_str(), "190202") != nullptr)
  //		special_key = true;
  // }

  {
    STACK_METRICS("Get CBrokerKey,capcity:%d", cache.capacity());
    cache_ptr->clear();
    if (!SSUserAccountManager::instance().IsBrokerMobileOnline()) {
      filter->BeforeReloads();
      BondID bid = source->GetFirstBondID();
      while (bid >= 0) {
        filter->ProcessBond(bid, this, cache_ptr);  // recv in OnBrokerKeyFound
        bid = source->GetNextBondID();
      }
      filter->AfterReloads();
    }
  }

  BLHCONDITION* pBlh = filter->GetCondition();
  if (pBlh && pBlh->nSettlement[0] > CBondContainer::StmAll &&
      pBlh->nSettlement[0] <= CBondContainer::StmMax) {
    BYTE btSettlement;
    switch (pBlh->nSettlement[0]) {
      case CBondContainer::StmT0:
        btSettlement = 0x1;
        break;
      case CBondContainer::StmT1:
        btSettlement = 0x2;
        break;
      case CBondContainer::StmFwd:
        btSettlement = 0x4;
        break;
      case CBondContainer::StmSpot:
        btSettlement = 0x3;
        break;
      default:
        btSettlement = 0x0;
        break;
    }
    SortImpl(*cache_ptr, btSettlement, true);
  } else {
    SortImpl(*cache_ptr, true);
  }
  // if (special_key)
  //{
  //	for (int i = 0; i < (int)cache_ptr->size(); i++)
  //	{
  //		BrokerKey bkey;
  //		cache_ptr->at(i).GetBrokerKey(bkey);
  //		Update(bkey, true);
  //	}
  // }
}

void CBrokerKeyList::ReloadsCFETS(int nType, CBondSource* source,
                                  CBondFilter* filter) {
  STACK_METRICS("ReloadsCFETS");
  // CSharedResourcePtr<CBrokerKeyCache> cache_ptr;
  CBrokerKeyCache cache;
  CBrokerKeyCache* cache_ptr = &cache;
  {
    STACK_METRICS("Get CBrokerKey,capcity:%d", cache.capacity());
    cache_ptr->clear();
    if (!SSUserAccountManager::instance().IsBrokerMobileOnline()) {
      BondID bid = source->GetFirstBondID();
      while (bid >= 0) {
        filter->ProcessBondCFETS(nType, bid, this,
                                 cache_ptr);  // recv in OnBrokerKeyFound
        bid = source->GetNextBondID();
      }
    }
  }
  SortImpl(*cache_ptr, true);
}

void CBrokerKeyList::ReloadsCFETSDeal(CBondSource* source,
                                      CBondFilter* filter) {
  STACK_METRICS("ReloadsCFETSDeal");
  // CSharedResourcePtr<CBrokerKeyCache> cache_ptr;
  CBrokerKeyCache cache;
  CBrokerKeyCache* cache_ptr = &cache;
  {
    STACK_METRICS("Get CBrokerKey,capcity:%d", cache.capacity());
    cache_ptr->clear();
    if (!SSUserAccountManager::instance().IsBrokerMobileOnline()) {
      BondID bid = source->GetFirstBondID();
      while (bid >= 0) {
        filter->ProcessBondCFETSDeal(bid, this,
                                     cache_ptr);  // recv in OnBrokerKeyFound
        bid = source->GetNextBondID();
      }
    }
  }
  SortImpl(*cache_ptr, true);
}

void CBrokerKeyList::ReloadsSSEFI(CBondSource* source, CBondFilter* filter) {
  STACK_METRICS("ReloadsCFETSDeal");
  // CSharedResourcePtr<CBrokerKeyCache> cache_ptr;
  CBrokerKeyCache cache;
  CBrokerKeyCache* cache_ptr = &cache;
  {
    STACK_METRICS("Get CBrokerKey,capcity:%d", cache.capacity());
    cache_ptr->clear();
    if (!SSUserAccountManager::instance().IsBrokerMobileOnline()) {
      BondID bid = source->GetFirstBondID();
      while (bid >= 0) {
        filter->ProcessBondSSEFI(bid, this,
                                 cache_ptr);  // recv in OnBrokerKeyFound
        bid = source->GetNextBondID();
      }
    }
  }
  SortImpl(*cache_ptr, true);
}

void CBrokerKeyList::Sort() {
  // 第一条两种方案
  // CSharedResourcePtr<CBrokerKeyCache> cache_ptr;

  CBrokerKeyCache cache;
  CBrokerKeyCache* cache_ptr = &cache;

  {
    STACK_METRICS("GetAllKeys");
    m_keys->GetAllKeys(*cache_ptr);
  }

  SortImpl(*cache_ptr, true);
}

void CBrokerKeyList::Sort(BYTE btSettlement) {
  // 第一条两种方案
  // CSharedResourcePtr<CBrokerKeyCache> cache_ptr;

  CBrokerKeyCache cache;
  CBrokerKeyCache* cache_ptr = &cache;

  {
    STACK_METRICS("GetAllKeys");
    m_keys->GetAllKeys(*cache_ptr);
  }

  SortImpl(*cache_ptr, btSettlement, true);
}

kJumpInsertWhere CBrokerKeyList::GetInsertWhere() {
  kJumpInsertWhere where = kJumpInsertWhereTail;
  if (m_sort_info.m_vecSortInfo.size() > 0) where = kJumpInsertWhereFind;
  return where;
}

void CBrokerKeyList::Update(const CBrokerKeyVector& keys, bool add) {
  // STACK_METRICS("Update,%d   add:%s",keys.size(),add?"true":"false");
  CBrokerKeyVector::const_iterator it = keys.begin();
  for (; it != keys.end(); ++it) {
    Update(*it, add);
  }
}
void CBrokerKeyList::Update(const CBrokerKeyVector& addKeys,
                            const CBrokerKeyVector& eraseKeys) {
  if (addKeys.size() <= 0 && eraseKeys.size() <= 0) return;
  vector<BrokerKeyInfo> keys;
  keys.reserve(addKeys.size() + eraseKeys.size());
  vector<bool> addOrErase;
  for (int i = 0; i < (int)addKeys.size(); i++) {
    keys.push_back(addKeys[i]);
    addOrErase.push_back(true);
  }
  for (int i = 0; i < (int)eraseKeys.size(); i++) {
    keys.push_back(eraseKeys[i]);
    addOrErase.push_back(false);
  }
  m_keys->UpdateBatch(keys, addOrErase);
}
void CBrokerKeyList::UpdateBatch(const std::vector<BrokerKeyInfo>& keys,
                                 const std::vector<bool>& addOrErase) {
  // STACK_METRICS("Update,%d   add:%s",keys.size(),add?"true":"false");
  m_keys->UpdateBatch(keys, addOrErase);
}
void CBrokerKeyList::Update(const BrokerKey& key, bool add) {
  if (add) {
    kJumpInsertWhere where = GetInsertWhere();
    if (where == kJumpInsertWhereFind && m_bond_sorter->GetRecordSize() <= 0) {
      vector<ColumnOrder> orders;
      GetColumnOrders(m_sort_info, orders);
      m_bond_sorter->SetSortInfo(orders);
    }

    m_keys->Insert(key, where);
  } else
    m_keys->Erase(key);
}
void CBrokerKeyList::PrintModifyTimes(const char* brokerid, bool before) {}
int CBrokerKeyList::GetRowCount() { return m_keys->GetCount(); }

int CBrokerKeyList::GetRecordKeys(int row, int count, BrokerKeyInfo* keys) {
  row = row < 0 ? 0 : row;
  if (count > 0) {
    return m_keys->GetKeys(row, count, keys);
  }
  return 0;
}
bool CBrokerKeyList::IsExist(const BrokerKeyInfo& key) {
  return m_keys->IsExist(key);
}
int CBrokerKeyList::GetVersion(const BrokerKeyInfo& key) {
  return m_keys->GetVersion(key);
}
void CBrokerKeyList::SortImpl(vector<BrokerKeyInfo>& keys, bool force) {
  vector<ColumnOrder> orders;
  GetColumnOrders(m_sort_info, orders);
  int ncorpid = atoi(m_sort_info.GetSortCorp());
  m_bond_sorter->Sort(orders, keys, ncorpid, force);
  int ncount = (int)keys.size();
  {
    STACK_METRICS("rebuild keys :%d,capcity:%d", keys.size(), keys.capacity());
    m_keys->BeginPush(keys.size());
    for (int i = 0; i < (int)keys.size(); i++) {
      m_keys->Push(keys[i]);
    }
    m_keys->EndPush(false);
  }
}

void CBrokerKeyList::SortImpl(vector<BrokerKeyInfo>& keys, BYTE btSettlement,
                              bool force) {
  vector<ColumnOrder> orders;
  GetColumnOrders(m_sort_info, orders);
  int ncorpid = atoi(m_sort_info.GetSortCorp());
  m_bond_sorter->Sort(orders, keys, btSettlement, ncorpid, force);
  int ncount = (int)keys.size();
  {
    STACK_METRICS("rebuild keys :%d,capcity:%d", keys.size(), keys.capacity());
    m_keys->BeginPush(keys.size());
    for (int i = 0; i < (int)keys.size(); i++) {
      m_keys->Push(keys[i]);
    }
    m_keys->EndPush(false);
  }
}
